package com.cmc.cloud.cmclink.doc.service.impl.special;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.cmc.cloud.cmclink.doc.api.document.emums.*;
import com.cmc.cloud.cmclink.doc.constants.CommonConstants;
import com.cmc.cloud.cmclink.doc.entity.*;
import com.cmc.cloud.cmclink.doc.mapper.*;
import com.cmc.cloud.cmclink.doc.service.special.EmailTaskService;
import com.cmc.cloud.cmclink.doc.util.EmailUtil;
import com.cmc.cloud.cmclink.doc.vo.EmailSendTaskBaseVO;
import com.cmc.cloud.cmclink.doc.vo.EmailSendTaskPageReqVO;
import com.cmc.cloud.cmclink.doc.vo.sovo.attachmentvo.AttachmentRespVO;
import com.cmc.cloud.cmclink.system.api.api.file.FileApi;
import com.cmes.framework.common.pojo.CommonResult;
import com.cmes.framework.common.pojo.PageResult;
import com.cmes.framework.common.util.json.JsonUtils;
import com.cmes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.mail.Address;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.Session;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import java.io.ByteArrayInputStream;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author huzheng
 * @Date 2025/10/01
 */
@Slf4j
@Service
public class EmailTaskServiceImpl implements EmailTaskService {
    @Resource
    private SpecialCargoVoyageMapper specialCargoVoyageMapper;
    @Resource
    private EmailSendTaskMapper emailSendTaskMapper;
    @Resource
    private SpecialCargoApplyMapper specialCargoApplyMapper;
    @Resource
    private SpecialCargoCntrMapper specialCargoCntrMapper;
    @Resource
    private SpecialCargoFlexiMapper specialCargoFlexiMapper;
    @Resource
    private SpecialCargoOogMapper specialCargoOogMapper;
    @Resource
    private SpecialCargoOdoMapper specialCargoOdoMapper;
    @Resource
    private SpecialCargoDgMapper specialCargoDgMapper;
    @Resource
    private PartnerSpecialCargoEmailMapper partnerSpecialCargoEmailMapper;
    @Resource
    private CargoCntrTypeRelationMapper cargoCntrTypeRelationMapper;
    @Resource
    private SpecialCargoDgExtMapper specialCargoDgExtMapper;
    @Resource
    private SpecialCargoDgPackingMapper specialCargoDgPackingMapper;
    @Resource
    private AttachmentMapper attachmentMapper;
    @Resource
    EmailUtil emailUtil;
    @Resource
    private FileApi fileApi;

    private static final SimpleDateFormat SDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    public static final String DEFULT_INTERVAL = "30";


    @Override
    public void createApplyEmailTask(Long applyId) {
        SpecialCargoApplyDO applyDo = specialCargoApplyMapper.selectById(applyId);
        List<SpecialCargoVoyageDO> voyageDos = specialCargoVoyageMapper.selectList(new LambdaQueryWrapper<SpecialCargoVoyageDO>()
                .eq(SpecialCargoVoyageDO::getApplyId, applyId).ne(SpecialCargoVoyageDO::getCarrier, CntrOwnerEnum.SNL.getValue()));
        if (CollectionUtil.isNotEmpty(voyageDos)) {
            List<EmailSendTaskDO> taskDOList = new ArrayList<>();
            for (SpecialCargoVoyageDO v : voyageDos) {
                EmailSendTaskDO taskDo = emailSendTaskMapper.selectOne(new LambdaQueryWrapperX<EmailSendTaskDO>().eq(EmailSendTaskDO::getApplyNo, applyDo.getApplyNo())
                        .eq(EmailSendTaskDO::getCarrier, v.getCarrier())
                        .eq(EmailSendTaskDO::getCargoType, applyDo.getApplyType())
                        .eq(EmailSendTaskDO::getEmailType, ApplyStatusEnum.PENDING.getValue())
                        .eq(EmailSendTaskDO::getSendStatus, EmailStatusEnum.PENDING.getValue()).orderByDesc(EmailSendTaskDO::getCreateTime).last("LIMIT 1"));
                if (null != taskDo) {
                    taskDo.setSendStatus(EmailStatusEnum.PENDING.getValue());
                    taskDo.setVesselCode(v.getVesselCode() + "/" + v.getVoyageEx());
                    taskDo.setPolCode(v.getPolCode());
                    taskDo.setPodCode(v.getPodCode());
                    taskDo.setDelCode(applyDo.getDelCode());
                    String partnerConfigEmail = getPartnerConfigEmail(v.getPolCode(), v.getCarrier(), v.getLaneCode(), applyDo.getApplyType());
                    taskDo.setRecipient(partnerConfigEmail);
                    emailSendTaskMapper.updateById(taskDo);
                    continue;
                }
                taskDo = new EmailSendTaskDO();
                taskDo.setApplyNo(applyDo.getApplyNo());
                taskDo.setBookingNo(applyDo.getBookingNo());
                taskDo.setSender(CntrOwnerEnum.SNL.getValue());
                taskDo.setSpaceOwner(applyDo.getSpaceOwner());
                taskDo.setEmailCc(CommonConstants.EMAIL_CC);
                taskDo.setVesselCode(v.getVesselCode() + "/" + v.getVoyageEx());
                taskDo.setPolCode(v.getPolCode());
                taskDo.setPodCode(v.getPodCode());
                taskDo.setDelCode(applyDo.getDelCode());
                taskDo.setCarrier(v.getCarrier());
                taskDo.setEmailType(ApplyStatusEnum.PENDING.getValue());
                taskDo.setCargoType(applyDo.getApplyType());
                taskDo.setSendStatus(EmailStatusEnum.PENDING.getValue());
                taskDo.setSendTimeInterval(DEFULT_INTERVAL);
                String partnerConfigEmail = getPartnerConfigEmail(v.getPolCode(), v.getCarrier(), v.getLaneCode(), applyDo.getApplyType());
                taskDo.setRecipient(partnerConfigEmail);
                taskDOList.add(taskDo);
            }
            emailSendTaskMapper.insertBatch(taskDOList);
        }

    }

    public String getPartnerConfigEmail(String polCode, String carrier, String laneCode, String applyType) {
        String recipient = CommonConstants.DEFAULT_EMAIL_SENDER;
        PartnerSpecialCargoEmailDO partnerEmailDo = partnerSpecialCargoEmailMapper.selectOne(new LambdaQueryWrapper<PartnerSpecialCargoEmailDO>()
                .eq(PartnerSpecialCargoEmailDO::getPol, polCode)
                .eq(PartnerSpecialCargoEmailDO::getPartnerCode, carrier)
                .like(PartnerSpecialCargoEmailDO::getLaneCodes, laneCode).last("LIMIT 1"));
        if (null != partnerEmailDo) {
            if (SpecialEnum.AK.getValue().equals(applyType)) {
                String oogEmails = partnerEmailDo.getOogEmails();
                if (StringUtils.isNotEmpty(oogEmails)) {
                    return oogEmails;
                }
            }
            if (SpecialEnum.ODO.getValue().equals(applyType)) {
                String odoEmails = partnerEmailDo.getOdoEmails();
                if (StringUtils.isNotEmpty(odoEmails)) {
                    return odoEmails;
                }
            }
            if (SpecialEnum.FLEXI.getValue().equals(applyType)) {
                String flexiEmails = partnerEmailDo.getFlexiEmails();
                if (StringUtils.isNotEmpty(flexiEmails)) {
                    return flexiEmails;
                }
            }
            if (SpecialEnum.DG.getValue().equals(applyType)) {
                String dgEmails = partnerEmailDo.getDgEmails();
                if (StringUtils.isNotEmpty(dgEmails)) {
                    return dgEmails;
                }
            }
        }
        return recipient;
    }

    public void getApprovalEmails(EmailSendTaskDO taskDo, Long applyId) {
        AttachmentDO attachmentDo = attachmentMapper.selectOne(new LambdaQueryWrapperX<AttachmentDO>().eq(AttachmentDO::getReferenceId, applyId)
                .eq(AttachmentDO::getReferenceType, SpecialEnum.SPC.getValue()).eq(AttachmentDO::getFileFormat, "eml").isNotNull(AttachmentDO::getFileId).orderByDesc(AttachmentDO::getCreateTime).last("LIMIT 1"));
        if (null != attachmentDo) {
            try {
                Map<String, String> emailSenders = getEmailSenders(attachmentDo.getFileId());
                String from = emailSenders.get("FROM");
                taskDo.setRecipient(from);
                String cc = emailSenders.get("CC");
                if (StringUtils.isNotEmpty(cc)) {
                    taskDo.setEmailCc(cc);
                }
            } catch (MessagingException e) {
                throw new RuntimeException("createApprovalEmailTaskError,ApplyId:" + applyId + " errorInfo:", e);
            }
        }
    }


    @Override
    public void createApprovalEmailTask(Long applyId) {
        SpecialCargoApplyDO applyDo = specialCargoApplyMapper.selectById(applyId);
        //集运方的审批同意不用发送邮件
        if (ApplyStatusEnum.APPROVED.getValue().equals(applyDo.getApplyStatus()) && CntrOwnerEnum.SNL.getValue().equals(applyDo.getSpaceOwner())) {
            return;
        }
        List<SpecialCargoVoyageDO> voyageDos = specialCargoVoyageMapper.selectList(new LambdaQueryWrapper<SpecialCargoVoyageDO>()
                .eq(SpecialCargoVoyageDO::getApplyId, applyId));
        LambdaQueryWrapperX<EmailSendTaskDO> wrapperX = new LambdaQueryWrapperX<EmailSendTaskDO>()
                .eq(EmailSendTaskDO::getApplyNo, applyDo.getApplyNo())
                .eq(EmailSendTaskDO::getCargoType, applyDo.getApplyType());
        if (ApprovalStatusEnum.PRECONSENT.getValue().equals(applyDo.getApproveStatus())) {
            wrapperX.eq(EmailSendTaskDO::getEmailType, applyDo.getApproveStatus());
        } else {
            wrapperX.eq(EmailSendTaskDO::getEmailType, applyDo.getApplyStatus());
        }
        wrapperX.eq(EmailSendTaskDO::getSendStatus, EmailStatusEnum.PENDING.getValue()).orderByDesc(EmailSendTaskDO::getCreateTime).last("LIMIT 1");
        EmailSendTaskDO taskDo = emailSendTaskMapper.selectOne(wrapperX);
        StringBuilder veslvoy = new StringBuilder(StringUtils.EMPTY);
        StringBuilder carrier = new StringBuilder(StringUtils.EMPTY);
        for (SpecialCargoVoyageDO voyageDo : voyageDos) {
            veslvoy.append(voyageDo.getVesselCode()).append("/").append(voyageDo.getVoyageEx()).append(",");
            carrier.append(voyageDo.getCarrier()).append(",");
        }
        if (null != taskDo) {
            taskDo.setVesselCode(veslvoy.toString());
            taskDo.setPolCode(applyDo.getPolCode());
            taskDo.setPodCode(applyDo.getPodCode());
            taskDo.setDelCode(applyDo.getDelCode());
            taskDo.setSendStatus(EmailStatusEnum.PENDING.getValue());
            taskDo.setRecipient(applyDo.getApplyEmail());
            if (!CntrOwnerEnum.SNL.getValue().equals(applyDo.getSpaceOwner())) {
                getApprovalEmails(taskDo, applyId);
            }
            emailSendTaskMapper.updateById(taskDo);
            return;
        }
        taskDo = new EmailSendTaskDO();
        taskDo.setEmailCc(CommonConstants.EMAIL_CC);
        taskDo.setRecipient(applyDo.getApplyEmail());
        if (!CntrOwnerEnum.SNL.getValue().equals(applyDo.getSpaceOwner())) {
            getApprovalEmails(taskDo, applyId);
        }
        taskDo.setApplyNo(applyDo.getApplyNo());
        taskDo.setBookingNo(applyDo.getBookingNo());
        taskDo.setSender(CntrOwnerEnum.SNL.getValue());
        taskDo.setCarrier(carrier.toString());
        if (!CntrOwnerEnum.SNL.getValue().equals(applyDo.getSpaceOwner())) {
            taskDo.setCarrier(CntrOwnerEnum.SNL.getValue());
        }
        taskDo.setVesselCode(veslvoy.toString());
        taskDo.setPolCode(applyDo.getPolCode());
        taskDo.setPodCode(applyDo.getPodCode());
        taskDo.setDelCode(applyDo.getDelCode());
        taskDo.setSpaceOwner(applyDo.getSpaceOwner());
        taskDo.setEmailType(applyDo.getApplyStatus());
        if (ApprovalStatusEnum.PRECONSENT.getValue().equals(applyDo.getApproveStatus())) {
            taskDo.setEmailType(applyDo.getApproveStatus());
        }
        taskDo.setCargoType(applyDo.getApplyType());
        taskDo.setSendStatus(EmailStatusEnum.PENDING.getValue());
        taskDo.setSendTimeInterval(DEFULT_INTERVAL);
        emailSendTaskMapper.insert(taskDo);
    }

    @Override
    public void cancelSend(List<Long> ids) {
        LambdaUpdateWrapper<EmailSendTaskDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(EmailSendTaskDO::getId, ids);
        updateWrapper.ne(EmailSendTaskDO::getSendStatus, EmailStatusEnum.SUCCESS.getValue());
        updateWrapper.set(EmailSendTaskDO::getSendStatus, EmailStatusEnum.CANCEL.getValue());
        emailSendTaskMapper.update(null, updateWrapper);
    }

    @Override
    public void updateSendInterval(String timeInterval) {
        LambdaUpdateWrapper<EmailSendTaskDO> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(EmailSendTaskDO::getSendTimeInterval, timeInterval);
        emailSendTaskMapper.update(null, updateWrapper);
    }

    @Override
    public String getSendInterval() {
        EmailSendTaskDO queryInterval = emailSendTaskMapper.selectOne(new LambdaQueryWrapper<EmailSendTaskDO>().orderByDesc(EmailSendTaskDO::getCreateTime).last("LIMIT 1"));
        String sendTimeInterval = DEFULT_INTERVAL;
        if (null != queryInterval) {
            sendTimeInterval = queryInterval.getSendTimeInterval();
        }
        return sendTimeInterval;
    }

    @Override
    public PageResult<EmailSendTaskBaseVO> getEmailSendTaskPage(EmailSendTaskPageReqVO reqVo) {
        LambdaQueryWrapperX<EmailSendTaskDO> queryWrapperX = new LambdaQueryWrapperX<EmailSendTaskDO>()
                .likeIfPresent(EmailSendTaskDO::getApplyNo, reqVo.getApplyNo())
                .likeIfPresent(EmailSendTaskDO::getVesselCode, reqVo.getVesselCode())
                .likeIfPresent(EmailSendTaskDO::getVesselCode, reqVo.getVoyageEx())
                .eqIfPresent(EmailSendTaskDO::getPolCode, reqVo.getPolCode())
                .eqIfPresent(EmailSendTaskDO::getBookingNo, reqVo.getBookingNo())
                .eqIfPresent(EmailSendTaskDO::getCargoType, reqVo.getCargoType())
                .eqIfPresent(EmailSendTaskDO::getSendStatus, reqVo.getSendStatus());
        if (null != reqVo.getApplyStartDate()) {
            queryWrapperX.ge(EmailSendTaskDO::getCreateTime, reqVo.getApplyStartDate());
        }
        if (null != reqVo.getApplyEndDate()) {
            queryWrapperX.le(EmailSendTaskDO::getCreateTime, reqVo.getApplyEndDate().plusDays(1));
        }
        if (null != reqVo.getSendStartDate()) {
            queryWrapperX.ge(EmailSendTaskDO::getSendTime, reqVo.getSendStartDate());
        }
        if (null != reqVo.getSendEndDate()) {
            queryWrapperX.le(EmailSendTaskDO::getSendTime, reqVo.getSendEndDate().plusDays(1));
        }
        queryWrapperX.orderByDesc(EmailSendTaskDO::getCreateTime);
        PageResult<EmailSendTaskDO> pageResult = emailSendTaskMapper.selectPage(reqVo, queryWrapperX);
        List<EmailSendTaskBaseVO> results = BeanUtil.copyToList(pageResult.getList(), EmailSendTaskBaseVO.class);
        return new PageResult<>(results, pageResult.getTotal());
    }

    @XxlJob("EmailSendTaskHandler")
    public void emailSendTask() {
        log.info("EmailSendTaskHandler_Send");
        LambdaQueryWrapper<EmailSendTaskDO> queryWrapper = new LambdaQueryWrapper<>();
        String sendTimeInterval = DEFULT_INTERVAL;
        EmailSendTaskDO queryInterval = emailSendTaskMapper.selectOne(new LambdaQueryWrapper<EmailSendTaskDO>().orderByDesc(EmailSendTaskDO::getCreateTime).last("LIMIT 1"));
        if (null != queryInterval) {
            sendTimeInterval = queryInterval.getSendTimeInterval();
        }
        LocalDateTime afterMinutes = LocalDateTime.now().minusMinutes(Long.parseLong(sendTimeInterval));
        queryWrapper.eq(EmailSendTaskDO::getSendStatus, EmailStatusEnum.PENDING.getValue());
        queryWrapper.le(EmailSendTaskDO::getCreateTime, afterMinutes);
        List<EmailSendTaskDO> emailSendTask = emailSendTaskMapper.selectList(queryWrapper);
        if (CollectionUtil.isNotEmpty(emailSendTask)) {
            Map<String, List<EmailSendTaskDO>> groupedByApplyNo = emailSendTask.stream()
                    .collect(Collectors.groupingBy(EmailSendTaskDO::getApplyNo));
            groupedByApplyNo.forEach((applyNo, taskList) -> taskList.forEach(task -> asyncEmailNotice(applyNo, task)));
        }
    }

    @Override
    public void reSend(List<Long> ids) {
        LambdaQueryWrapper<EmailSendTaskDO> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.in(EmailSendTaskDO::getId, ids);
        List<EmailSendTaskDO> emailSendTask = emailSendTaskMapper.selectList(queryWrapper);
        if (CollectionUtil.isNotEmpty(emailSendTask)) {
            Map<String, List<EmailSendTaskDO>> groupedByApplyNo = emailSendTask.stream()
                    .collect(Collectors.groupingBy(EmailSendTaskDO::getApplyNo));
            groupedByApplyNo.forEach((applyNo, taskList) -> taskList.forEach(task -> asyncEmailNotice(applyNo, task)));
        }

    }

    public void asyncEmailNotice(String applyNo, EmailSendTaskDO task) {
        LambdaQueryWrapperX<SpecialCargoApplyDO> specialCargoApplyWrapperX = new LambdaQueryWrapperX<>();
        specialCargoApplyWrapperX.eq(SpecialCargoApplyDO::getApplyNo, applyNo).orderByDesc(SpecialCargoApplyDO::getCreateTime).last("LIMIT 1");
        SpecialCargoApplyDO applyDo = specialCargoApplyMapper.selectOne(specialCargoApplyWrapperX);
        String emailType = task.getEmailType();
        String templateCode = StringUtils.EMPTY;
        HashMap<String, Object> templateParams = new HashMap<>(16);
        List<SpecialCargoCntrDO> cntrDos = specialCargoCntrMapper.selectList(new LambdaQueryWrapper<SpecialCargoCntrDO>().eq(SpecialCargoCntrDO::getApplyId, applyDo.getId())
                .orderByAsc(SpecialCargoCntrDO::getCreateTime));
        List<Long> cntrIds = cntrDos.stream().map(SpecialCargoCntrDO::getId).collect(Collectors.toList());
        templateParams.put("emailTitle", applyNo + "/" + task.getVesselCode() + "/" + task.getVoyageEx() + "/" + applyDo.getPolCode() + "/" + applyDo.getPodCode() + "/" + applyDo.getReferenceNo());
        templateParams.put("applyTime", SDF.format(applyDo.getApplyTime()));
        templateParams.put("bookingNo", applyDo.getBookingNo());
        templateParams.put("vslvoy", task.getVesselCode() + "/" + task.getVoyageEx());
        templateParams.put("polCode", applyDo.getPolCode());
        templateParams.put("podCode", applyDo.getPodCode());
        templateParams.put("delCode", applyDo.getDelCode());
        if (ApplyStatusEnum.PENDING.getValue().equals(emailType)) {
            if (SpecialEnum.AK.getValue().equals(applyDo.getApplyType())) {
              /*  String partnerConfigEmail = getPartnerConfigEmail(task.getPolCode(), task.getCarrier(), task.getVesselCode(), applyDo.getApplyType());
                if (StringUtils.isNotEmpty(partnerConfigEmail)) {
                    task.setRecipient(partnerConfigEmail);
                }*/
                List<SpecialCargoOogDO> oogDos = specialCargoOogMapper.selectList(new LambdaQueryWrapper<SpecialCargoOogDO>().in(SpecialCargoOogDO::getCntrId, cntrIds));
                Map<Long, SpecialCargoOogDO> oogDoMap = oogDos.stream().collect(Collectors.toMap(SpecialCargoOogDO::getCntrId, e -> e));
                templateCode = "oogPartnerApply";
                StringBuilder notice = new StringBuilder();
                for (SpecialCargoCntrDO cntr : cntrDos) {
                    SpecialCargoOogDO oogDO = oogDoMap.get(cntr.getId());
                    if (null != oogDO) {
                        notice.append("<p>CONTAINER QTY / TPSZ:").append(cntr.getQty()).append("×").append(cntr.getCntrSize()).append(cntr.getCntrType()).append("</p>\n\n");
                        notice.append("--------------------------------------\n\n");
                        notice.append("<p>&nbsp;&nbsp; Commodity: ").append(oogDO.getCargoDescription()).append("</p>\n\n");
                        notice.append("<p>&nbsp;&nbsp; Gross Weight :").append(cntr.getGrossWgt()).append("KGS</p>\n\n");
                        notice.append("<p>&nbsp;&nbsp; Net Weight :").append(cntr.getNetWgt()).append("KGS</p>\n\n");
                        notice.append("<p>&nbsp;&nbsp; Overall Dimension(in cm) : (Length × Width × Height)</p>\n\n");
                        notice.append("<p>&nbsp;&nbsp; 1) Total : ").append(oogDO.getOverallLength()).append("×").append(oogDO.getOverallWidth()).append("×").append(oogDO.getOverallHeight()).append("</p>\n\n");
                        notice.append("<p>&nbsp;&nbsp; Over Dimension(in cm) :</p>\n");
                        notice.append("<p>&nbsp;&nbsp; 1) Forward : ").append(oogDO.getOverForward()).append("</p>\n\n");
                        notice.append("<p>&nbsp;&nbsp; 2) After  : ").append(oogDO.getOverAfter()).append("</p>\n\n");
                        notice.append("<p>&nbsp;&nbsp; 3) Height : ").append(oogDO.getOverHeight()).append("</p>\n\n");
                        notice.append("<p>&nbsp;&nbsp; 4) Left (Port Side) : ").append(oogDO.getOverLeft()).append("</p>\n\n");
                        notice.append("<p>&nbsp;&nbsp; 5) Right (Starboard) : ").append(oogDO.getOverRight()).append("</p>\n\n");
                        notice.append("<p>&nbsp;&nbsp; Corner Post Status : ").append(oogDO.getCornerPostStatus()).append("</p>\n");
                        notice.append("<p>&nbsp;&nbsp; Special Stowage Requirement : ").append(oogDO.getSpecialStorageRequire()).append("</p>\n\n");
                    }
                }
                templateParams.put("cargoDetails", notice);
                sendEmail(task, templateCode, templateParams);
                return;
            }
            if (SpecialEnum.ODO.getValue().equals(applyDo.getApplyType())) {
                /*String partnerConfigEmail = getPartnerConfigEmail(task.getPolCode(), task.getCarrier(), task.getVesselCode(), applyDo.getApplyType());
                if (StringUtils.isNotEmpty(partnerConfigEmail)) {
                    task.setRecipient(partnerConfigEmail);
                }*/
                List<SpecialCargoOdoDO> odoDos = specialCargoOdoMapper.selectList(new LambdaQueryWrapper<SpecialCargoOdoDO>().in(SpecialCargoOdoDO::getCntrId, cntrIds));
                Map<Long, SpecialCargoOdoDO> odoDoMap = odoDos.stream().collect(Collectors.toMap(SpecialCargoOdoDO::getCntrId, e -> e));
                templateCode = "odoPartnerApply";
                StringBuilder notice = new StringBuilder();
                for (SpecialCargoCntrDO cntr : cntrDos) {
                    SpecialCargoOdoDO odoDo = odoDoMap.get(cntr.getId());
                    if (null != odoDo) {
                        notice.append("<p>CONTAINER QTY / TPSZ:").append(cntr.getQty()).append("×").append(cntr.getCntrSize()).append(cntr.getCntrType()).append("</p>\n\n");
                        notice.append("--------------------------------------\n\n");
                        notice.append("<p>&nbsp;&nbsp; Commodity: ").append(odoDo.getCargoDescription()).append("</p>\n\n");
                        notice.append("<p>&nbsp;&nbsp; &nbsp;&nbsp; Gross weight :").append(cntr.getGrossWgt()).append("KGS</p>\n\n");
                        notice.append("<p>&nbsp;&nbsp; &nbsp;&nbsp; Net weight :").append(cntr.getNetWgt()).append("KGS</p>\n\n");
                        notice.append("<p>&nbsp;&nbsp; DOOR OPEN LEFT OR RIGHT :").append(odoDo.getOpenDirection()).append("</p>\n\n");
                        notice.append("<p>&nbsp;&nbsp; DOOR :").append(odoDo.getDoorRemove()).append("</p>\n\n");
                        notice.append("<p>&nbsp;&nbsp; OPEN ANGLE :").append(odoDo.getOpenAngle()).append("</p>\n\n");
                    }
                }
                List<AttachmentRespVO> attachmentList = attachmentMapper.getAttachmentInfos(applyDo.getId(), SoSiEnum.SPC.getValue());
                if (CollectionUtil.isNotEmpty(attachmentList)) {
                    String attachments = attachmentList.stream().map(AttachmentRespVO::getAttachName).collect(Collectors.joining(","));
                    notice.append("<p>&nbsp;&nbsp;注：客户提供的附件有</p>");
                    notice.append("<p>").append(attachments).append("</p>");
                }
                templateParams.put("cargoDetails", notice);
                sendEmail(task, templateCode, templateParams);
                return;
            }
            if (SpecialEnum.FLEXI.getValue().equals(applyDo.getApplyType())) {
                /*String partnerConfigEmail = getPartnerConfigEmail(task.getPolCode(), task.getCarrier(), task.getVesselCode(), applyDo.getApplyType());
                if (StringUtils.isNotEmpty(partnerConfigEmail)) {
                    task.setRecipient(partnerConfigEmail);
                }*/
                List<SpecialCargoFlexiDO> flexiDos = specialCargoFlexiMapper.selectList(new LambdaQueryWrapper<SpecialCargoFlexiDO>().in(SpecialCargoFlexiDO::getCntrId, cntrIds));
                Map<Long, SpecialCargoFlexiDO> flexiDoMap = flexiDos.stream().collect(Collectors.toMap(SpecialCargoFlexiDO::getCntrId, e -> e));
                templateCode = "flexiPartnerApply";
                StringBuilder notice = new StringBuilder();
                for (SpecialCargoCntrDO cntr : cntrDos) {
                    SpecialCargoFlexiDO flexiDo = flexiDoMap.get(cntr.getId());
                    if (null != flexiDo) {
                        notice.append("<p>CONTAINER QTY / TPSZ:").append(cntr.getQty()).append("×").append(cntr.getCntrSize()).append(cntr.getCntrType()).append("</p>\n\n");
                        notice.append("--------------------------------------\n\n");
                        notice.append("<p>&nbsp;&nbsp; Commodity: ").append(flexiDo.getCargoDescription()).append("</p>\n\n");
                        notice.append("<p>&nbsp;&nbsp; &nbsp;&nbsp; Gross Weight :").append(cntr.getGrossWgt()).append("KGS</p>\n\n");
                        notice.append("<p>&nbsp;&nbsp; &nbsp;&nbsp; Net Weight :").append(cntr.getNetWgt()).append("KGS</p>\n\n");
                        notice.append("<p>&nbsp;&nbsp; Capacity of flexitank (litres) :").append(flexiDo.getCapacityOfFlexitank()).append("</p>\n\n");
                        notice.append("<p>&nbsp;&nbsp; Volume of cargo (litres) :").append(flexiDo.getVolumeOfCargo()).append("</p>\n\n");
                        notice.append("<p>&nbsp;&nbsp; Loading ratio :").append(flexiDo.getLoadingRatio()).append("</p>\n\n");
                        notice.append("<p>&nbsp;&nbsp; Product name :").append(" ").append("</p>\n\n");
                        notice.append("<p>&nbsp;&nbsp; Density :").append(" ").append("</p>\n\n");
                        notice.append("<p>&nbsp;&nbsp; Name of the flexitank manufacturer :").append(flexiDo.getNameOfManufacturer()).append("</p>\n\n");
                        notice.append("<p>&nbsp;&nbsp; Loading requirements / handling :").append(" ").append("</p>\n\n");
                    }
                }
                List<AttachmentRespVO> attachmentList = attachmentMapper.getAttachmentInfos(applyDo.getId(), SoSiEnum.SPC.getValue());
                if (CollectionUtil.isNotEmpty(attachmentList)) {
                    String attachments = attachmentList.stream().map(AttachmentRespVO::getAttachName).collect(Collectors.joining(","));
                    notice.append("<p>&nbsp;&nbsp;注：客户提供的附件有</p>");
                    notice.append("<p>").append(attachments).append("</p>");
                }
                templateParams.put("cargoDetails", notice);
                sendEmail(task, templateCode, templateParams);
                return;
            }
            if (SpecialEnum.DG.getValue().equals(applyDo.getApplyType())) {
                /*String partnerConfigEmail = getPartnerConfigEmail(task.getPolCode(), task.getCarrier(), task.getVesselCode(), applyDo.getApplyType());
                if (StringUtils.isNotEmpty(partnerConfigEmail)) {
                    task.setRecipient(partnerConfigEmail);
                }*/
                List<SpecialCargoDgDO> dgDos = specialCargoDgMapper.selectList(new LambdaQueryWrapper<SpecialCargoDgDO>().eq(SpecialCargoDgDO::getApplyId, applyDo.getId()));
                Map<Long, SpecialCargoDgDO> dgMap = dgDos.stream().collect(Collectors.toMap(SpecialCargoDgDO::getId, e -> e));
                List<Long> dgIds = dgDos.stream().map(SpecialCargoDgDO::getId).collect(Collectors.toList());
                List<CargoCntrTypeRelationDO> relationDos = cargoCntrTypeRelationMapper.selectList(new LambdaQueryWrapper<CargoCntrTypeRelationDO>()
                        .eq(CargoCntrTypeRelationDO::getApplyId, applyDo.getId()).in(CargoCntrTypeRelationDO::getDgId, dgIds));
                Map<Long, List<CargoCntrTypeRelationDO>> dgCntrMap = relationDos.stream().collect(Collectors.groupingBy(CargoCntrTypeRelationDO::getDgId));
                templateCode = "dgPartnerApply";
                StringBuilder notice = new StringBuilder();
                for (Long dgId : dgCntrMap.keySet()) {
                    List<CargoCntrTypeRelationDO> dgCntr = dgCntrMap.get(dgId);
                    List<Long> cntrRelationIds = dgCntr.stream().map(CargoCntrTypeRelationDO::getCntrId).collect(Collectors.toList());
                    List<SpecialCargoCntrDO> cntrDgDos = specialCargoCntrMapper.selectList(new LambdaQueryWrapper<SpecialCargoCntrDO>()
                            .eq(SpecialCargoCntrDO::getApplyId, applyDo.getId()).in(SpecialCargoCntrDO::getId, cntrRelationIds));
                    Map<String, List<SpecialCargoCntrDO>> cntrMap = cntrDgDos.stream().collect(Collectors.groupingBy(cntr -> cntr.getCntrSize() + cntr.getCntrType()));
                    for (String cntrSizeType : cntrMap.keySet()) {
                        List<SpecialCargoCntrDO> specialCargoCntrDos = cntrMap.get(cntrSizeType);
                        BigDecimal grossWt = BigDecimal.ZERO;
                        BigDecimal netWt = BigDecimal.ZERO;
                        Integer cntrNum = 0;
                        for (SpecialCargoCntrDO cntrInfo : specialCargoCntrDos) {
                            grossWt = grossWt.add(cntrInfo.getGrossWgt());
                            netWt = netWt.add(cntrInfo.getNetWgt());
                            cntrNum = cntrNum + cntrInfo.getQty();
                        }
                        notice.append("<p>CONTAINER QTY / TPSZ:").append(cntrNum).append("×").append(cntrSizeType).append("</p>\n\n");
                        notice.append("<p>&nbsp;&nbsp; &nbsp;&nbsp; Gross WT :").append(grossWt).append("KGS</p>\n\n");
                        notice.append("<p>&nbsp;&nbsp; &nbsp;&nbsp; NET WT :").append(netWt).append("KGS</p>\n\n");
                    }
                    SpecialCargoDgDO dg = dgMap.get(dgId);
                    List<SpecialCargoDgPackingDO> packingDos = specialCargoDgPackingMapper.selectList(new LambdaQueryWrapperX<SpecialCargoDgPackingDO>().eq(SpecialCargoDgPackingDO::getDgId, dgId));
                    String innerPacking = packingDos.stream().filter(packing -> PackingEnum.INNER.getValue().equals(packing.getPackingType())).map(SpecialCargoDgPackingDO::getPackings).collect(Collectors.joining(","));
                    String outerPacking = packingDos.stream().filter(packing -> PackingEnum.OUTER.getValue().equals(packing.getPackingType())).map(SpecialCargoDgPackingDO::getPackings).collect(Collectors.joining(","));
                    notice.append("--------------------------------------\n\n");
                    notice.append("<p>&nbsp;&nbsp; IMO CLASS :").append(dg.getImoClass()).append("</p>\n\n");
                    notice.append("<p>&nbsp;&nbsp; UN NO. :").append(dg.getUnNo()).append("</p>\n\n");
                    notice.append("<p>&nbsp;&nbsp; PROPER SHIPPING NAME :").append(dg.getPsn()).append("</p>\n\n");
                    notice.append("<p>&nbsp;&nbsp; TECHNICAL NAME :").append(dg.getTechnicalName()).append("</p>\n\n");
                    notice.append("<p>&nbsp;&nbsp; PACKING GROUP :").append(dg.getPackingGroup()).append("</p>\n\n");
                    notice.append("<p>&nbsp;&nbsp; SUBSIDIARY RISK :").append(dg.getSubsidiaryRisk()).append("</p>\n\n");
                    notice.append("<p>&nbsp;&nbsp; DG GROSS WT. :").append(dg.getDgGrossWgt()).append("KGS</p>\n\n");
                    notice.append("<p>&nbsp;&nbsp; DG NET WT. :").append(dg.getDgNetWgt()).append("KGS</p>\n\n");
                    notice.append("<p>&nbsp;&nbsp; NET EXPLOSIVE WT. :").append(dg.getNetExplosiveWgt()).append("KGS</p>\n\n");
                    notice.append("<p>&nbsp;&nbsp; OUTER PACKAGINGS :").append(outerPacking).append("</p>\n\n");
                    notice.append("<p>&nbsp;&nbsp; INNER PACKAGINGS :").append(innerPacking).append("</p>\n\n");
                    notice.append("<p>&nbsp;&nbsp; SEGREGATION GROUP :").append(dg.getSegregationGroup()).append("</p>\n\n");
                    notice.append("<p>&nbsp;&nbsp; LIMITED QUANTITY :").append(dg.getLimitedQty()).append("</p>\n\n");
                    notice.append("<p>&nbsp;&nbsp; FLASH POINT :").append(dg.getFlashPoint()).append("℃</p>\n\n");
                    notice.append("<p>&nbsp;&nbsp; MARINE POLLUTANT :").append(dg.getMarinePollutant()).append("</p>\n\n");
                    notice.append("<p>&nbsp;&nbsp; EMS TABLE NUMBER :").append(dg.getEmsNo()).append("</p>\n\n");
                    notice.append("<p>&nbsp;&nbsp; ERG :").append(dg.getErg()).append("</p>\n\n");
                    notice.append("<p>&nbsp;&nbsp; EMERGENCY CONTACT :")
                            .append(dg.getEmergencyContactName()).append(";")
                            .append(dg.getEmergencyContactAddress()).append(";")
                            .append(dg.getEmergencyContactMobile())
                            .append("</p>\n\n");
                    notice.append("<p>&nbsp;&nbsp; MFAGNO :").append(dg.getMfagNo()).append("</p>\n\n");
                    notice.append("<p>&nbsp;&nbsp; CARGOSTATUS :").append(dg.getCargoStatus()).append("</p>\n\n");
                    List<SpecialCargoDgExtDO> dgExtDOList = specialCargoDgExtMapper.selectList(new LambdaQueryWrapperX<SpecialCargoDgExtDO>().eq(SpecialCargoDgExtDO::getDgId, dg.getId()));
                    if (CollectionUtil.isNotEmpty(dgExtDOList)) {
                        for (SpecialCargoDgExtDO dgExtDo : dgExtDOList) {
                            notice.append("<p>&nbsp;&nbsp; ").append(dgExtDo.getExtName()).append("&nbsp:&nbsp").append(dgExtDo.getExtValue()).append("</p>\n\n");
                        }
                    }
                }
                templateParams.put("cargoDetails", notice);
                sendEmail(task, templateCode, templateParams);
                return;
            }
        }
        templateParams.put("referenceNo", applyDo.getReferenceNo());
        templateParams.put("spaceOwner", applyDo.getSpaceOwner());
        if (!CntrOwnerEnum.SNL.getValue().equals(applyDo.getSpaceOwner()) &&
                (ApplyStatusEnum.APPROVED.getValue().equals(emailType) || ApprovalStatusEnum.PRECONSENT.getValue().equals(emailType))) {
            if (SpecialEnum.AK.getValue().equals(applyDo.getApplyType())) {
                templateCode = "oogApproved";
                if (ApprovalStatusEnum.PRECONSENT.getValue().equals(emailType)) {
                    templateCode = "oogPerApprove";
                }
                sendEmail(task, templateCode, templateParams);
                return;
            }
            if (SpecialEnum.ODO.getValue().equals(applyDo.getApplyType())) {
                templateCode = "odoApproved";
                sendEmail(task, templateCode, templateParams);
                return;
            }
            if (SpecialEnum.FLEXI.getValue().equals(applyDo.getApplyType())) {
                List<SpecialCargoFlexiDO> flexiDOList = specialCargoFlexiMapper.selectList(new LambdaQueryWrapper<SpecialCargoFlexiDO>().in(SpecialCargoFlexiDO::getCntrId, cntrIds));
                Map<Long, SpecialCargoFlexiDO> cntr2FlexiMap = flexiDOList.stream().collect(Collectors.toMap(SpecialCargoFlexiDO::getCntrId, e -> e));
                StringBuilder notice = new StringBuilder();
                notice.append("<table border=\"1\" cellpadding=\"5\" cellspacing=\"0\">\n");
                notice.append("<tr>\n");
                notice.append("<th><b>CNTR. Size</b></th>\n");
                notice.append("<th><b>CNTR. Type</b></th>\n");
                notice.append("<th><b>QTY.</b></th>\n");
                notice.append("<th><b>Gross Weight(kg)</b></th>\n");
                notice.append("<th><b>Manufacturer of Flexitank</b></th>\n");
                notice.append("<th><b>Stowage Request</b></th>\n");
                notice.append("<th><b>Commodity</b></th>\n");
                notice.append("</tr>\n");
                for (SpecialCargoCntrDO cntrDo : cntrDos) {
                    notice.append("<tr>\n");
                    notice.append("<td>").append(cntrDo.getCntrSize()).append("</td>\n");
                    notice.append("<td>").append(cntrDo.getCntrType()).append("</td>\n");
                    notice.append("<td>").append(cntrDo.getQty()).append("</td>\n");
                    notice.append("<td>").append(cntrDo.getGrossWgt()).append("</td>\n");
                    SpecialCargoFlexiDO flexiDO = cntr2FlexiMap.get(cntrDo.getId());
                    notice.append("<td>").append(flexiDO.getNameOfManufacturer()).append("</td>\n");
                    notice.append("<td>").append("Stowage Request").append("</td>\n");
                    notice.append("<td>").append(flexiDO.getCargoDescription()).append("</td>\n");
                    notice.append("</tr>\n");
                }
                notice.append("</table>");
                templateCode = "flexiApproved";
                templateParams.put("cargoDetails", notice);
                sendEmail(task, templateCode, templateParams);
                return;
            }
            if (SpecialEnum.DG.getValue().equals(applyDo.getApplyType())) {
                templateCode = "dgApproved";
                sendEmail(task, templateCode, templateParams);
                return;
            }
        }
        List<SpecialCargoVoyageDO> voyageDOList = specialCargoVoyageMapper.selectList(new LambdaQueryWrapper<SpecialCargoVoyageDO>()
                .eq(SpecialCargoVoyageDO::getApplyId, applyDo.getId()).orderByAsc(SpecialCargoVoyageDO::getRouteNo));
        if (ApplyStatusEnum.REJECT.getValue().equals(emailType)) {
            String rejectReason = voyageDOList.stream().filter(voyage -> ApplyStatusEnum.REJECT.getValue().equals(voyage.getRouteApproveStatus()))
                    .findFirst().get().getApproveRemark();
            StringBuilder reason = new StringBuilder();
            reason.append("<b><font color='red'>")
                    .append(rejectReason)
                    .append("</font></b>");
            if (SpecialEnum.AK.getValue().equals(applyDo.getApplyType())) {
                if (CntrOwnerEnum.SNL.getValue().equals(applyDo.getSpaceOwner())) {
                    templateCode = "oogRejected";
                } else {
                    templateCode = "oogPartnerRejected";
                }
                templateParams.put("rejectReason", reason);
                sendEmail(task, templateCode, templateParams);
                return;
            }
            if (SpecialEnum.ODO.getValue().equals(applyDo.getApplyType())) {
                if (CntrOwnerEnum.SNL.getValue().equals(applyDo.getSpaceOwner())) {
                    templateCode = "odoRejected";
                } else {
                    templateCode = "odoPartnerRejected";
                }
                templateParams.put("rejectReason", reason);
                sendEmail(task, templateCode, templateParams);
                return;
            }
            if (SpecialEnum.FLEXI.getValue().equals(applyDo.getApplyType())) {
                List<SpecialCargoFlexiDO> flexiDOList = specialCargoFlexiMapper.selectList(new LambdaQueryWrapper<SpecialCargoFlexiDO>().in(SpecialCargoFlexiDO::getCntrId, cntrIds));
                Map<Long, SpecialCargoFlexiDO> cntr2FlexiMap = flexiDOList.stream().collect(Collectors.toMap(SpecialCargoFlexiDO::getCntrId, e -> e));
                StringBuilder notice = new StringBuilder();
                notice.append("<table border=\"1\" cellpadding=\"5\" cellspacing=\"0\">\n");
                notice.append("<tr>\n");
                notice.append("<th><b>CNTR. Size</b></th>\n");
                notice.append("<th><b>CNTR. Type</b></th>\n");
                notice.append("<th><b>QTY.</b></th>\n");
                notice.append("<th><b>Gross Weight(kg)</b></th>\n");
                notice.append("<th><b>Manufacturer of Flexitank</b></th>\n");
                notice.append("<th><b>Stowage Request</b></th>\n");
                notice.append("<th><b>Commodity</b></th>\n");
                notice.append("</tr>\n");
                for (SpecialCargoCntrDO cntrDO : cntrDos) {
                    notice.append("<tr>\n");
                    notice.append("<td>").append(cntrDO.getCntrSize()).append("</td>\n");
                    notice.append("<td>").append(cntrDO.getCntrType()).append("</td>\n");
                    notice.append("<td>").append(cntrDO.getQty()).append("</td>\n");
                    notice.append("<td>").append(cntrDO.getGrossWgt()).append("</td>\n");
                    SpecialCargoFlexiDO flexiDO = cntr2FlexiMap.get(cntrDO.getId());
                    notice.append("<td>").append(flexiDO.getNameOfManufacturer()).append("</td>\n");
                    notice.append("<td>").append("Stowage Request").append("</td>\n");
                    notice.append("<td>").append(flexiDO.getCargoDescription()).append("</td>\n");
                    notice.append("</tr>\n");
                }
                notice.append("</table>");
                templateCode = "flexiRejected";
                templateParams.put("rejectReason", reason);
                templateParams.put("cargoDetails", notice);
                sendEmail(task, templateCode, templateParams);
                return;
            }
            if (SpecialEnum.DG.getValue().equals(applyDo.getApplyType())) {
                templateCode = "dgRejected";
                templateParams.put("rejectReason", reason);
                sendEmail(task, templateCode, templateParams);
                return;
            }
        }
        String rejectReason = voyageDOList.stream().map(SpecialCargoVoyageDO::getApproveRemark)
                .filter(approveRemark -> approveRemark != null && !approveRemark.isEmpty()).collect(Collectors.joining(","));
        StringBuilder reason = new StringBuilder();
        reason.append("<b><font color='red'>")
                .append(rejectReason)
                .append("</font></b>");
        if (ApplyStatusEnum.ADD_INFO.getValue().equals(emailType)) {
            if (SpecialEnum.AK.getValue().equals(applyDo.getApplyType())) {
                templateCode = "oogAddInfo";
            }
            if (SpecialEnum.ODO.getValue().equals(applyDo.getApplyType())) {
                templateCode = "odoAddInfo";
            }
            if (SpecialEnum.FLEXI.getValue().equals(applyDo.getApplyType())) {
                List<SpecialCargoFlexiDO> flexiDOList = specialCargoFlexiMapper.selectList(new LambdaQueryWrapper<SpecialCargoFlexiDO>().in(SpecialCargoFlexiDO::getCntrId, cntrIds));
                Map<Long, SpecialCargoFlexiDO> cntr2FlexiMap = flexiDOList.stream().collect(Collectors.toMap(SpecialCargoFlexiDO::getCntrId, e -> e));
                StringBuilder notice = new StringBuilder();
                notice.append("<table border=\"1\" cellpadding=\"5\" cellspacing=\"0\">\n");
                notice.append("<tr>\n");
                notice.append("<th><b>CNTR. Size</b></th>\n");
                notice.append("<th><b>CNTR. Type</b></th>\n");
                notice.append("<th><b>QTY.</b></th>\n");
                notice.append("<th><b>Gross Weight(kg)</b></th>\n");
                notice.append("<th><b>Manufacturer of Flexitank</b></th>\n");
                notice.append("<th><b>Stowage Request</b></th>\n");
                notice.append("<th><b>Commodity</b></th>\n");
                notice.append("</tr>\n");
                for (SpecialCargoCntrDO cntrDO : cntrDos) {
                    notice.append("<tr>\n");
                    notice.append("<td>").append(cntrDO.getCntrSize()).append("</td>\n");
                    notice.append("<td>").append(cntrDO.getCntrType()).append("</td>\n");
                    notice.append("<td>").append(cntrDO.getQty()).append("</td>\n");
                    notice.append("<td>").append(cntrDO.getGrossWgt()).append("</td>\n");
                    SpecialCargoFlexiDO flexiDO = cntr2FlexiMap.get(cntrDO.getId());
                    notice.append("<td>").append(flexiDO.getNameOfManufacturer()).append("</td>\n");
                    notice.append("<td>").append("Stowage Request").append("</td>\n");
                    notice.append("<td>").append(flexiDO.getCargoDescription()).append("</td>\n");
                    notice.append("</tr>\n");
                }
                notice.append("</table>");
                templateParams.put("cargoDetails", notice);
                templateCode = "flexiAddInfo";
            }
            if (SpecialEnum.DG.getValue().equals(applyDo.getApplyType())) {
                templateCode = "dgAddInfo";
            }
            templateParams.put("rejectReason", reason);
            sendEmail(task, templateCode, templateParams);
            return;
        }
        if (ApplyStatusEnum.ADD_ATTACHMENT.getValue().equals(emailType)) {
            if (SpecialEnum.AK.getValue().equals(applyDo.getApplyType())) {
                templateCode = "oogAddAttach";
            }
            if (SpecialEnum.ODO.getValue().equals(applyDo.getApplyType())) {
                templateCode = "odoAddAttach";
            }
            if (SpecialEnum.FLEXI.getValue().equals(applyDo.getApplyType())) {
                List<SpecialCargoFlexiDO> flexiDOList = specialCargoFlexiMapper.selectList(new LambdaQueryWrapper<SpecialCargoFlexiDO>().in(SpecialCargoFlexiDO::getCntrId, cntrIds));
                Map<Long, SpecialCargoFlexiDO> cntr2FlexiMap = flexiDOList.stream().collect(Collectors.toMap(SpecialCargoFlexiDO::getCntrId, e -> e));
                StringBuilder notice = new StringBuilder();
                notice.append("<table border=\"1\" cellpadding=\"5\" cellspacing=\"0\">\n");
                notice.append("<tr>\n");
                notice.append("<th><b>CNTR. Size</b></th>\n");
                notice.append("<th><b>CNTR. Type</b></th>\n");
                notice.append("<th><b>QTY.</b></th>\n");
                notice.append("<th><b>Gross Weight(kg)</b></th>\n");
                notice.append("<th><b>Manufacturer of Flexitank</b></th>\n");
                notice.append("<th><b>Stowage Request</b></th>\n");
                notice.append("<th><b>Commodity</b></th>\n");
                notice.append("</tr>\n");
                for (SpecialCargoCntrDO cntrDO : cntrDos) {
                    notice.append("<tr>\n");
                    notice.append("<td>").append(cntrDO.getCntrSize()).append("</td>\n");
                    notice.append("<td>").append(cntrDO.getCntrType()).append("</td>\n");
                    notice.append("<td>").append(cntrDO.getQty()).append("</td>\n");
                    notice.append("<td>").append(cntrDO.getGrossWgt()).append("</td>\n");
                    SpecialCargoFlexiDO flexiDO = cntr2FlexiMap.get(cntrDO.getId());
                    notice.append("<td>").append(flexiDO.getNameOfManufacturer()).append("</td>\n");
                    notice.append("<td>").append("Stowage Request").append("</td>\n");
                    notice.append("<td>").append(flexiDO.getCargoDescription()).append("</td>\n");
                    notice.append("</tr>\n");
                }
                notice.append("</table>");
                templateParams.put("cargoDetails", notice);
                templateCode = "flexiAddAttach";
            }
            if (SpecialEnum.DG.getValue().equals(applyDo.getApplyType())) {
                templateCode = "dgAddAttach";
            }
            templateParams.put("rejectReason", reason);
            sendEmail(task, templateCode, templateParams);
        }
    }

    public void sendEmail(EmailSendTaskDO task, String templateCode, Map<String, Object> templateParams) {
        String[] email = task.getRecipient().split(";");
        log.info("spcSendMailEmailCc: {},{}, templateCode: {}, templateParams: {}", task.getRecipient(), task.getEmailCc(), templateCode,
                JsonUtils.toJsonString(templateParams));
        List<MultipartFile> attachments = new ArrayList<>();
        Arrays.stream(email).forEach(e -> emailUtil.spcSendMail(e, task.getEmailCc(), templateCode, templateParams, attachments));
        task.setSendTime(LocalDateTime.now());
        task.setSendStatus(EmailStatusEnum.SUCCESS.getValue());
        emailSendTaskMapper.updateById(task);
    }

    public Map<String, String> getEmailSenders(Long fileId) throws MessagingException {
        CommonResult<byte[]> fileBinary = fileApi.getFileBinary(fileId);
        Properties props = new Properties();
        Session session = Session.getDefaultInstance(props, null);
        Map<String, String> senderMaps = new HashMap<>(8);
        ByteArrayInputStream inputStream = new ByteArrayInputStream(fileBinary.getData());
        MimeMessage mimeMessage = new MimeMessage(session, inputStream);
        Address[] fromAddresses = mimeMessage.getFrom();
        Address[] ccAddress = mimeMessage.getRecipients(Message.RecipientType.CC);
        if (fromAddresses != null) {
            senderMaps.put("FROM", getSenderCc(fromAddresses));
        }
        if (ccAddress != null) {
            senderMaps.put("CC", getSenderCc(ccAddress));
        }
        return senderMaps;
    }

    public String getSenderCc(Address[] address) {
        List<String> emails = new ArrayList<>();
        for (Address adder : address) {
            if (adder instanceof InternetAddress) {
                String email = ((InternetAddress) adder).getAddress();
                if (email != null && !email.isEmpty()) {
                    emails.add(email);
                }
            }
        }
        return String.join(";", emails);
    }
}
